// 焦点管理器核心
(function (window) {
  'use strict';
  var _keyEnum = { LEFT: "LEFT", UP: "UP", RIGHT: "RIGHT", DOWN: "DOWN", ENTER: "ENTER", BACK: "BACK", HOME: "HOME", BACKSPACE: "BACKSPACE", DEL: "DEL", MENU: "MENU" }
  //基础配置信息
  var _defConfig = {
    keyEnum: _keyEnum,
    keyDownTimeout: 60,//每次按键间隔
    animateTimeout: 200,//动画时长
    keyMap: { 65: _keyEnum.LEFT, 37: _keyEnum.LEFT, 87: _keyEnum.UP, 38: _keyEnum.UP, 68: _keyEnum.RIGHT, 39: _keyEnum.RIGHT, 83: _keyEnum.DOWN, 40: _keyEnum.DOWN, 13: _keyEnum.ENTER, 32: _keyEnum.BACK, 8: _keyEnum.BACK, 36: _keyEnum.HOME, 12: _keyEnum.BACKSPACE, 280: _keyEnum.DEL, 287: _keyEnum.DEL, 18: _keyEnum.MENU, 48: 0, 49: 1, 50: 2, 51: 3, 52: 4, 53: 5, 54: 6, 55: 7, 56: 8, 57: 9, },
    switchClass: "focusSwitch",//焦点框架
    popupClass: "focusPopup",//焦点弹窗
    boxClass: "focusBox",//盒子
    scrollClass: "focusScroll",//滚动区域
    virtualClass: "focusVirtual",//虚拟列表+滚动区域
    widgetClass: "focusWidget",//焦点元素
    marqueeClass: "focusMarquee",//跑马灯
    focusClass: "is-focus",//聚焦样式名
    focusBoxClass: "is-focusbox",//盒子元素聚焦样式名
    darkFocusClass: "dark-focus",//暗焦样式名
  }
  // 工具方法 --------------------------------------------------
  var Utils = {
    findInfo: function (list, fn) {
      var _itm = { index: -1, item: null };
      for (var i = 0; i < list.length; i++) {
        var _el = list[i];
        if (typeof fn === "function" && fn(_el, i)) {
          _itm.index = i;
          _itm.item = _el;
          break;
        }
      }
      return _itm;
    },
    find: function (list, fn) {
      return Utils.findInfo(list, fn).item
    },
    findIndex: function (list, fn) {
      return Utils.findInfo(list, fn).index
    },
    filter: function (list, fn) {
      var _list = [];
      for (var i = 0; i < list.length; i++) {
        var _el = list[i];
        if (typeof fn === "function" && fn(_el, i)) {
          _list.push(_el);
        }
      }
      return _list;
    },
    forEach: function (list, callback) {
      for (var i = 0; i < list.length; i++) {
        (function (index) {
          callback(list[index], index, list);
        })(i);
      }
    },
    map: function (list, callback) {
      var _list = []
      for (var i = 0; i < list.length; i++) {
        (function (index) {
          _list.push(callback(list[index], index, list) || list[index])
        })(i);
      }
      return _list
    },
    arrayConcat: function (list, list1) {
      this.forEach(list1, function (e) { list.push(e) })
      return list;
    },
    objConcat: function (v, v1) {
      this.forObjEach(v1, function (k, vv) { v[k] = vv })
      return v;
    },
    forObjEach: function (_obj, callback) {
      var _object = {}
      for (var key in _obj) {
        (function (_key) {
          var _ele = _obj[_key];
          _object[_key] = _ele
          callback(_key, _ele)
        })(key);
      }
      return _object
    },
    nextTick: function (fn) { return setTimeout(fn, 0); },
    $: function (_id) { return document.getElementById(_id) },
    $class: function (className, ctx) {
      return (ctx || document).getElementsByClassName(className);
    },
    getCurrentStyle: function (element, styleProp) {
      if (element.currentStyle) {
        return element.currentStyle[styleProp];
      } else if (window.getComputedStyle) {
        return window.getComputedStyle(element, null).getPropertyValue(styleProp);
      } else {
        return element.style[styleProp];
      }
    },
    isEleHide: function (ele) {
      if (typeof ele === "string") ele = Utils.$(ele)
      if (ele.style.display === "none") return true
      if (ele.style.visibility === "hidden") return true
      if (Utils.getCurrentStyle(ele, "display") === "none") return true
      if (Utils.getCurrentStyle(ele, "visibility") === "hidden") return true
      if (ele.offsetWidth === 0 || ele.offsetHeight === 0) return true
      return false
    },
    getRect: function (dom) {
      var _val = dom.getBoundingClientRect();
      return {
        centerX: _val.width / 2 + _val.left, centerY: _val.height / 2 + _val.top, bottom: _val.bottom, cacheBottom: _val.bottom, height: _val.height, left: _val.left, cacheLeft: _val.left,
        right: _val.right, cacheRight: _val.right, top: _val.top, cacheTop: _val.top, width: _val.width, x: _val.x, y: _val.y,
      };
    },
    getUid: function () {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
      });
    },
    getDomId: function (dom) {
      if (!dom) return null
      if (!dom.id) dom.id = this.getUid()
      return dom.id
    },
    getKeyValue: function (_code, keys) {
      var _keyboard = keys || _defConfig.keyMap;
      return _keyboard[_code];
    },
    eventListener: function (dom, eventName, callback) {
      if (dom.addEventListener) {
        dom.addEventListener(eventName, callback, false);
      } else if (dom.attachEvent) {
        dom.attachEvent("on" + eventName, callback);
      }
    },
    requestAnimationFrame: function (step) {
      step = typeof step === "function" ? step : function () { };
      if (window.requestAnimationFrame) {
        return window.requestAnimationFrame(step);
      } else {
        return setTimeout(step, 16);
      }
    },
    cancelAnimationFrame: function (id) {
      if (window.cancelAnimationFrame) {
        window.cancelAnimationFrame(id);
      } else {
        clearTimeout(id);
      }
    },
    observeDOMChanges: function (callback, targetNode) {
      var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
      var observer;
      targetNode = targetNode || document.documentElement; // 默认监听整个文档

      // MutationObserver 实现
      if (MutationObserver) {
        observer = new MutationObserver(function (mutations) {
          callback(mutations);
        });

        var config = {
          childList: true,
          subtree: true,
          // attributes: true,
          characterData: true
        };

        observer.observe(targetNode, config); // 监听指定节点
        return observer;
      }

      // 降级方案
      var events = [
        'DOMSubtreeModified',
        'DOMNodeInserted',
        'DOMNodeRemoved',
        // 'DOMAttrModified'
      ];

      var handler = function (event) {
        callback([{
          type: event.type,
          target: event.target,
          addedNodes: event.type === 'DOMNodeInserted' ? [event.target] : [],
          removedNodes: event.type === 'DOMNodeRemoved' ? [event.target] : []
        }]);
      };
      // 事件绑定到目标节点
      for (var i = 0; i < events.length; i++) {
        this.eventListener(targetNode, events[i], handler);
      }
      return {
        disconnect: function () {
          if (targetNode.removeEventListener) {
            for (var i = 0; i < events.length; i++) {
              targetNode.removeEventListener(events[i], handler, false);
            }
          } else if (targetNode.detachEvent) {
            for (var i = 0; i < events.length; i++) {
              targetNode.detachEvent('on' + events[i], handler);
            }
          }
        }
      };
    },
    animate: function (element, targetPosition, duration, property, callback) {
      property = property || 'left';
      var startPosition = parseInt(Utils.getCurrentStyle(element, property));
      var distance = targetPosition - startPosition;
      var startTime = new Date().getTime();
      var animationId;
      var _this = this;
      var step = function () {
        var elapsed = new Date().getTime() - startTime;
        var progress = elapsed / duration;
        progress = progress > 1 ? 1 : progress;
        element.style[property] = (startPosition + distance * progress) + 'px';
        if (progress < 1) {
          animationId = _this.requestAnimationFrame(step);
        } else {
          _this.cancelAnimationFrame(animationId);
          if (typeof callback === "function") callback();
        }
      };
      animationId = this.requestAnimationFrame(step);
      // 返回一个立即完成动画的函数
      var finishImmediately = function () {
        _this.cancelAnimationFrame(animationId);
        element.style[property] = targetPosition + 'px'; // 直接设置到目标位置
        if (typeof callback === "function") {
          callback(); // 执行回调
        }
      };
      return {
        animateId: animationId,
        finishImmediately: finishImmediately
      };
    },
    shakeElement: function (element) {
      var direction = arguments[1] || 'X';
      var amplitude = arguments[2] || 5;
      var duration = arguments[3] || 100;
      var iterations = arguments[4] || 2;
      var animationName = 'shake' + (new Date()).getTime() + Math.floor(Math.random() * 1e6);
      var style = document.createElement('style');
      style.type = 'text/css';
      var keyframes = [
        '@keyframes ', animationName, ' {',
        '0%, 100% { transform: translate(0, 0); }',
        '25% { transform: translate',
        direction,
        '(-', amplitude, 'px); }',
        '75% { transform: translate',
        direction,
        '(', amplitude, 'px); }',
        '}'
      ].join('');
      style.appendChild(document.createTextNode(keyframes));
      document.getElementsByTagName('head')[0].appendChild(style);
      element.style.cssText += ';animation:' + animationName + ' ' +
        (duration / 1000) + 's ease-in-out ' + iterations + ';';
      var cleanup = function () {
        element.style.cssText = element.style.cssText.replace(/animation[^;]+;?/g, '');
        try {
          document.getElementsByTagName('head')[0].removeChild(style);
        } catch (e) { }
      };
      this.eventListener(element, 'animationend', cleanup);
      this.eventListener(element, 'animationcancel', cleanup);
    },
    /** 计算焦点元素距离顶部或者最左侧的位置
     * @param {{ domLen: number,  parentLen: number,  childLen: number,  eleOffsetStart: number,  childOffsetStart: number,  offset: string | number,  fx: { value: "start" | "end" }, }} params 
     */
    calculateScroll: function (params) {
      var scrollno = 0;
      if (params.parentLen >= params.childLen) return scrollno;
      if (params.offset === "center") {
        scrollno = -(params.eleOffsetStart + params.domLen * 0.5 - params.parentLen / 2);
      } else if (typeof params.offset === "number") {
        var _startNo = -(params.eleOffsetStart - params.offset);
        var _endNo = -(params.eleOffsetStart - (params.parentLen - params.offset - params.domLen));
        if (params.childOffsetStart <= _startNo) {
          params.fx = "start";
        } else if (params.childOffsetStart >= _endNo) {
          params.fx = "end";
        }
        params.fx === "end" ? scrollno = _endNo : scrollno = _startNo;
      }
      if (scrollno > 0) {
        scrollno = 0;
      } else if (scrollno < -params.childLen + params.parentLen) {
        scrollno = -params.childLen + params.parentLen;
      }
      return parseInt(scrollno);
    },
    //字符串函数的解析
    eval: {
      onEval: function (fnStr, defParams) {
        if (typeof fnStr === "string") {
          var _params = this.parseByString(fnStr)
          if (defParams != null) {
            _params.args.push(defParams);
          }
          var func = this.resolveFunction(_params.funcName, window);
          if (typeof func === "function") {
            return func.apply(window, _params.args);
          }
        }
      },
      //从window中取到对应的函数
      resolveFunction: function (path, context) {
        var parts = path.split('.');
        var current = context, _bindThis = null;
        for (var i = 0; i < parts.length; i++) {
          if (current && typeof current === 'object' && current[parts[i]] !== undefined) {
            _bindThis = current
            current = current[parts[i]];
          } else {
            return null;
          }
        }
        if (typeof current === 'function') {
          if (_bindThis != null && (typeof _bindThis === "object")) return current.bind(_bindThis)
          return current
        }
        return null;
      },
      //将函数字符串解析为函数名与参数合集
      parseByString: function (input) {
        var hasParentheses = input.indexOf('(') !== -1 && input.indexOf(')') !== -1;
        if (hasParentheses) {
          // 修改正则表达式，允许函数名包含点号
          var regex = /^([\w.]+)\((.*)\)$/;
          var match = input.match(regex);
          if (match) {
            var funcName = match[1];
            var paramsString = match[2];
            try {
              var jsonArrayStr = '[' + paramsString.replace(/'/g, '"') + ']';
              var params = JSON.parse(jsonArrayStr);
              return { funcName: funcName, args: params };
            } catch (e) {
              var paramArray = this.splitParams(paramsString);
              var params = [];
              for (var i = 0; i < paramArray.length; i++) {
                var param = this.parseSingleParam(paramArray[i]);
                params.push(param);
              }
              return { funcName: funcName, args: params };
            }
          }
        } else {
          return { funcName: input, args: [] };
        }
        return null;
      },
      // 按逗号切割参数，处理简单场景（不处理嵌套逗号）
      splitParams: function (paramsString) {
        var parts = [];
        var current = '';
        var inQuotes = false;
        for (var i = 0; i < paramsString.length; i++) {
          var char = paramsString[i];
          if (char === ',' && !inQuotes) {
            parts.push(current);
            current = '';
          } else {
            if (char === '"' || char === "'") inQuotes = !inQuotes;
            current += char;
          }
        }
        parts.push(current);
        return parts;
      },
      // 解析单个参数：替换单引号 → 尝试 JSON.parse → 失败则返回原始字符串（去空格）
      parseSingleParam: function (rawParam) {
        var trimmed = rawParam.replace(/^\s+|\s+$/g, '');
        if (!trimmed) return null;
        try {
          var normalized = trimmed.replace(/'/g, '"');
          return JSON.parse(normalized);
        } catch (e) {
          try {
            return JSON.parse(trimmed);
          } catch (e2) {
            return trimmed;
          }
        }
      }
    },
    //文字滚动
    marquee: {
      marqueeTimer: {},
      spacing: 20,
      className: _defConfig.marqueeClass,
      contentClass: _defConfig.marqueeClass + "-content",
      contentItemClass: _defConfig.marqueeClass + "-content-item",
      createHtmlStrY: function (_defhtml) {
        var _newHtml = "<div class='" + this.contentItemClass + "' style='padding-bottom:" + this.spacing + "px'>" + _defhtml + "</div>"
        return "<div class='" + this.contentClass + "' style='position: absolute;left:0;top:0;'>" + _newHtml + _newHtml + '</div>'
      },
      createHtmlStrX: function (_defhtml) {
        var _newHtml = '<div class="' + this.contentItemClass + '" style="display:inline-block;padding-right:' + this.spacing + 'px;">' + _defhtml + '</div>'
        return '<div class="' + this.contentClass + '" style="position: absolute;left:0;top:0;">' + _newHtml + _newHtml + '</div>'
      },
      createDom: function (_dom, _html) {
        var _info = null
        var _content = Utils.$class(this.contentClass, _dom)//修改dom结构，用于滚动
        if (!_content || !_content[0]) {
          _dom.innerHTML = _html
          _content = Utils.$class(this.contentClass, _dom)
          if (!_content || !_content[0]) return _info
        }
        _content = _content[0]
        if (!_content) return _info
        var _itemDom = Utils.$class(this.contentItemClass, _dom)//修改dom结构，用于滚动
        if (!_itemDom || !_itemDom[0]) return _info
        _info = {
          child: _content,
          itemDom: _itemDom[0],
        }
        return _info
      },
      /**
       * 停止文字滚动
       * @param {string} _id 
       * @param {object | undefined} options 
       * { 
       *  reset: bool  是否复位 默认 = true
       * }
       * @returns 
       */
      stop: function (_id, options) {
        var _timer = this.marqueeTimer[_id]
        if (!_timer) return
        var _this = this
        Utils.cancelAnimationFrame(_timer)
        Utils.nextTick(function () {
          var _marqueeEle = Utils.$(_id)
          if (!_marqueeEle) return
          var _marqueeList = Utils.$class(_this.className, _marqueeEle)
          if (!_marqueeList || !_marqueeList[0]) _marqueeList = [_marqueeEle]
          Utils.forEach(_marqueeList, function (marqueeDom) {
            if (!options || options.reset !== true) return
            var _dir = (marqueeDom.getAttribute("marqueedir") === "Y") ? "Y" : "X"
            if (_dir === "X") {
              if (marqueeDom.scrollWidth <= marqueeDom.clientWidth) return
            } else {
              if (marqueeDom.scrollHeight <= marqueeDom.clientHeight) return
            }
            var _content = Utils.$class(_this.contentClass, marqueeDom)
            _content = _content[0]
            if (_content) {
              if (_dir === "X") {
                _content.style.left = 0 + "px";
              } else {
                _content.style.top = 0 + "px";
              }
            }
          })
          delete _this.marqueeTimer[_id]
        });
      },
      /** 停止文字滚动并且还原 */
      restore: function (_id) { return this.stop(_id, { reset: true }) },
      /**
       * 开始文字滚动
       * @param {string} _id 
       * @param {object | undefined} options 
       * { 
       *  speed: number,  速度 默认=60像素每秒
       * }
       * @returns 
       */
      start: function (_id, options) {
        var _this = this;
        var _marqueeList = [],
          _marqueeEle = Utils.$(_id),
          _speed = (options && options.speed && options.speed > 0) ? options.speed : 60
        if (!_marqueeEle) return
        _marqueeList = Utils.$class(_this.className, _marqueeEle)
        if (!_marqueeList || !_marqueeList[0]) _marqueeList = [_marqueeEle]
        Utils.cancelAnimationFrame(_this.marqueeTimer[_id] ? _this.marqueeTimer[_id] : "")
        delete _this.marqueeTimer[_id]
        var _list = []
        Utils.forEach(_marqueeList, function (marqueeDom) {
          var _dir = (marqueeDom.getAttribute("marqueedir") === "Y") ? "Y" : "X"
          var _domInfo = null, _htmlstr = ""
          if (_dir === "X") {
            if (marqueeDom.scrollWidth <= marqueeDom.clientWidth) return
            _htmlstr = _this.createHtmlStrX(marqueeDom.innerHTML)
          } else {
            if (marqueeDom.scrollHeight <= marqueeDom.clientHeight) return
            _htmlstr = _this.createHtmlStrY(marqueeDom.innerHTML)
          }
          _domInfo = _this.createDom(marqueeDom, _htmlstr)
          if (!_domInfo) return
          _domInfo["dir"] = _dir
          _domInfo["marqueeDom"] = marqueeDom
          if (_domInfo) _list.push(_domInfo)
        })
        if (_list.length > 0) {
          //每毫秒移动的像素，速度
          var startTime = new Date().getTime();
          var _step = function () {
            var endTime = new Date().getTime();
            Utils.forEach(_list, function (val) {
              if (val.dir === "X") {
                var _pos = val.child.style.left.replace("px", "")
                if (_pos < -val.itemDom.offsetWidth) { _pos = 0 }
                val.child.style.left = (_pos - ((_speed / 1000) * (endTime - startTime))) + "px"
              } else {
                var _pos = val.child.style.top.replace("px", "")
                if (_pos < -val.itemDom.offsetHeight) { _pos = 0 }
                val.child.style.top = (_pos - ((_speed / 1000) * (endTime - startTime))) + "px"
              }
            })
            startTime = endTime
            _this.marqueeTimer[_id] = Utils.requestAnimationFrame(_step)
          }
          _this.marqueeTimer[_id] = Utils.requestAnimationFrame(_step)
        }
      }
    }
  };
  //内部组件公共方法
  var _baseFn = {
    /**
     * 获取滚动元素内的元素更新后的焦点位置信息
     * @param {*} dir 
     * @param {*} no 
     */
    getRectInScroll: function (rect, dir, no) {
      //更新内部焦点元素的位置信息
      if (dir === "X") {
        rect.left = rect.cacheLeft + no
        rect.x = rect.left
        rect.centerX = rect.width / 2 + rect.left
        rect.right = rect.cacheRight + no
      } else {
        rect.top = rect.cacheTop + no
        rect.y = rect.top
        rect.centerY = rect.height / 2 + rect.top
        rect.bottom = rect.cacheBottom + no
      }
      return rect
    },
    //定向跳转-适用于盒子组件与焦点组件
    moveByAppoint: function (self, curWidget, nextWidget, key) {
      var _newFocus = null;
      var _onLeft = self.getAttr(self.attrs.onLeft)
      var _onRight = self.getAttr(self.attrs.onRight)
      var _onUp = self.getAttr(self.attrs.onUp)
      var _onDown = self.getAttr(self.attrs.onDown)
      var _params = { target: self, key: key, curWidget: curWidget, nextWidget: nextWidget }
      if (typeof _onLeft === "string" && key === _defConfig.keyEnum.LEFT) _newFocus = Utils.eval.onEval(_onLeft, _params)
      if (typeof _onRight === "string" && key === _defConfig.keyEnum.RIGHT) _newFocus = Utils.eval.onEval(_onRight, _params)
      if (typeof _onUp === "string" && key === _defConfig.keyEnum.UP) _newFocus = Utils.eval.onEval(_onUp, _params)
      if (typeof _onDown === "string" && key === _defConfig.keyEnum.DOWN) _newFocus = Utils.eval.onEval(_onDown, _params)
      if (_newFocus) return _newFocus
      var _eleIds = "";
      if (key === _defConfig.keyEnum.LEFT) {
        _eleIds = self.getAttr(self.attrs.goLeft);
      } else if (key === _defConfig.keyEnum.RIGHT) {
        _eleIds = self.getAttr(self.attrs.goRight);
      } else if (key === _defConfig.keyEnum.UP) {
        _eleIds = self.getAttr(self.attrs.goUp);
      } else if (key === _defConfig.keyEnum.DOWN) {
        _eleIds = self.getAttr(self.attrs.goDown);
      }
      if (!_eleIds) return _newFocus;
      _eleIds = _eleIds.split(",");
      Utils.find(_eleIds, function (_goId) {
        _newFocus = Utils.find(self.options.commontens[self.name] || [], function (ev) { return (ev.id === _goId && !Utils.isEleHide(ev.container)) })
        return _newFocus
      })
      return _newFocus;
    },
    //计算元素滚动元素的位置
    getScrollNo: function (self, _item, _scrollDir) {
      var scrollNumber = 0, _nowScrollNumber = 0, _scrollParams = {}
      var _focuspos = parseInt(_item.getAttribute("f-focuspos"))
      var _posdomid = _item.getAttribute("f-posdomid")
      if(_posdomid != null && (isNaN(_focuspos) || _focuspos == null)){
        _posdomid = Utils.$(_posdomid);
        if(_posdomid != null) _item = _posdomid;
      }
      if (!isNaN(_focuspos) && _focuspos != null) {
        scrollNumber = _focuspos;
        _nowScrollNumber = self.scrollContent[_scrollDir == "X" ? "offsetLeft" : "offsetTop"];
      } else {
        if (_scrollDir === "X") {
          _scrollParams = {
            domLen: Utils.getRect(_item).width,
            parentLen: Utils.getRect(self.container).width,
            childLen: Utils.getRect(self.scrollContent).width,
            eleOffsetStart: _item.offsetLeft,
            childOffsetStart: self.scrollContent.offsetLeft,
            offset: parseFloat(self.getAttr(self.attrs.offsetNum)) || "center",
            fx: self.getAttr(self.attrs.centerPostion) || "start"
          }
          scrollNumber = Utils.calculateScroll(_scrollParams);
          _nowScrollNumber = self.scrollContent.offsetLeft;
        } else {
          _scrollParams = {
            domLen: Utils.getRect(_item).height,
            parentLen: Utils.getRect(self.container).height,
            childLen: Utils.getRect(self.scrollContent).height,
            eleOffsetStart: _item.offsetTop,
            childOffsetStart: self.scrollContent.offsetTop,
            offset: parseFloat(self.getAttr(self.attrs.offsetNum)) || "center",
            fx: self.getAttr(self.attrs.centerPostion) || "start"
          }
          scrollNumber = Utils.calculateScroll(_scrollParams);
          _nowScrollNumber = self.scrollContent.offsetTop;
        }
      }
      return {
        number: scrollNumber,
        oldNumber: _nowScrollNumber
      }
    }
  }
  /**默认组件列表 */
  var _DefCommontens = {
    /**
     * 焦点盒子
     */
    [_defConfig.boxClass]: function FocusBox(container, options) {
      this.options = options || {}
      this.container = container
      this.name = _defConfig.boxClass
      this.id = Utils.getDomId(this.container)
      this.rect = Utils.getRect(this.container)
      this.attrs = {
        cacheRect: "f-cacherect",//是否缓存组件的位置大小信息,缓存之后，下次组件更新生命周期发生时（onUpdate）将不会更新此组件的位置信息。(<div f-cacherect="true"></div>)
        cacheDir: "f-cachedir",//焦点缓存方向--可配置LEFT,RIGHT,UP,DOWN四个方向，默认为空，则缓存所有方向-依赖于f-cache。(<div f-cachedir="UP,DOWN"></div>)
        cacheWidget: "f-cache",//配置缓存焦点的id，是否缓存焦点，若未找到缓存的焦点，则初始化不缓存焦点，焦点移入后缓存最后移出该盒子时的焦点。(<div f-cache="widgetid"></div>)
        sequenceRow: "f-sequencerow",//用于盒子内部的焦点元素的顺序计算，指定每行有多少个元素，若不配置此项，则不开启此功能。(<div f-sequencerow="1"></div>)
        sequenceLink: "f-sequencelink",//盒子内部的焦点启用顺序计算时，当移动到每一行的首尾时，是否仍然按照顺序移动。(<div f-sequencelink="true"></div>)
        onDarkFocus: "ondarkfocus",
        //焦点移出之前的函数，可返回焦点盒子(指定焦点移出时的下一个盒子，移出后的焦点必定是指定的下一个盒子内部的焦点)，或者true（控制不进行跳转）//(<div onleft="fn()"></div>)
        onLeft: "onleft", onRight: "onright", onUp: "onup", onDown: "ondown", onFocus: "onfocus", onBlur: "onblur",
        //指定盒子元素移出时聚焦的下一个的焦点盒子元素，多个盒子元素以,分割，优先查找第一个盒子元素的id，未找到时查找下一个
        goLeft: "f-goleft", goRight: "f-goright", goUp: "f-goup", goDown: "f-godown",
      }
      this.getAttr = this.container.getAttribute.bind(this.container)
      this.setAttr = this.container.setAttribute.bind(this.container)
      this.cacheRect = this.getAttr(this.attrs.cacheRect) === "true"
      this.getCacheWidget = function (_key) {
        //查看是否有缓存方向的配置项
        var _cacheDir = this.getAttr(this.attrs.cacheDir)
        _cacheDir = _cacheDir ? _cacheDir.split(",") : null
        var _cache = this.getAttr(this.attrs.cacheWidget)
        //如果有缓存的焦点，直接跳转到缓存的焦点
        if (_cache && (!_cacheDir || Utils.find(_cacheDir, function (_el) { return _el === _key }))) {
          return Utils.find(this.options.commontens[_defConfig.widgetClass] || [], function (_el) { return (_el.id === _cache); });
        }
        return null
      }
      //滚动组件滚动时，更新rect信息
      this.onScrollMove = function (scrollBox, moveNo) {
        this.rect = _baseFn.getRectInScroll(this.rect, scrollBox.scrollDir, moveNo)
      }
      /** * 焦点计算，顺序计算,仅对同一个盒子内部的元素有效 */
      this.onSequenceAlgorithm = function (_fItem, direction) {
        var _newfItem = null
        if (!_fItem || !_fItem.widgetBox || _fItem.widgetBox != this) return _newfItem;
        //指定每行有多少个元素
        var _sequenceRow = this.getAttr(this.attrs.sequenceRow);
        //滚动到左右边界时，是否还是进行顺序滚动
        var _sequenceLink = this.getAttr(this.attrs.sequenceLink);
        if (!_sequenceRow || _sequenceRow <= 0) return _newfItem
        _sequenceRow = _sequenceRow * 1;
        var _widgetEleListInBox = Utils.filter(this.options.commontens[_defConfig.widgetClass], function (ev) {
          return ev.widgetBox && ev.widgetBox.container && ev.widgetBox === _fItem.widgetBox
        })
        var _focusInBox = Utils.findInfo(_widgetEleListInBox, function (ev) { return ev.id === _fItem.id })
        if (!_focusInBox.item) return _newfItem
        var _domIdx = -1
        if (direction === _defConfig.keyEnum.UP) {
          _domIdx = _focusInBox.index > 0 ? _focusInBox.index - _sequenceRow : -1;
        } else if (direction === _defConfig.keyEnum.LEFT) {
          if ((_sequenceLink === "false") && (_focusInBox.index % _sequenceRow === 0)) {
            _domIdx = -1
          } else {
            _domIdx = _focusInBox.index >= 0 ? _focusInBox.index - 1 : -1;
          }
        } else if (direction === _defConfig.keyEnum.RIGHT) {
          if ((_sequenceLink === "false") && ((_focusInBox.index + 1) % _sequenceRow === 0)) {
            _domIdx = -1
          } else {
            _domIdx = (_focusInBox.index < _widgetEleListInBox.length) ? _focusInBox.index + 1 : -1;
          }
        } else if (direction === _defConfig.keyEnum.DOWN) {
          _domIdx = (_focusInBox.index < (_widgetEleListInBox.length - _sequenceRow)) ? (_focusInBox.index + _sequenceRow) : -1;
        }
        _newfItem = _widgetEleListInBox[_domIdx]
        return _newfItem;
      }
      this.setDarkFocus = function (_widget, _isInit, _needEmit) {
        if (!_widget || !_widget.widgetBox || !this.container.contains(_widget.container) || !this.getAttr(this.attrs.cacheWidget)) return
        this.praveDarkContainerId = this.getAttr(this.attrs.cacheWidget)
        this.setAttr(this.attrs.cacheWidget, _widget.id)
        //初始化暗焦
        this.onSetDarkClass(_isInit, _needEmit)
      }
      /**设置暗焦样式，如果在滚动区域，则滚动到可视位置 */
      this.onSetDarkClass = function (isInit, _needEmit) {
        var _cacheId = this.getAttr(this.attrs.cacheWidget)
        if (!_cacheId) return
        var _this = this, _cacheConteniner = null
        if (_this.container.contains(this.options.focusItem ? this.options.focusItem.container : null)) {
          _cacheConteniner = this.options.focusItem.container
        } else {
          _cacheConteniner = Utils.$(_cacheId)
        }
        if (!_cacheConteniner) return
        if (this.praveDarkContainerId && this.praveDarkContainerId != _cacheId) {
          var _praveDarkDom = Utils.$(this.praveDarkContainerId)
          if (_praveDarkDom) _praveDarkDom.classList.remove(_defConfig.darkFocusClass)
        } else if (this.praveDarkContainerId != _cacheId || _needEmit) {
          Utils.eval.onEval(this.getAttr(this.attrs.onDarkFocus), { target: this, cacheConteniner: _cacheConteniner, isInit: isInit, curWidget: this.options.focusItem })
        }
        _cacheConteniner.classList.add(_defConfig.darkFocusClass)
        if (this.praveDarkContainerId !== _cacheConteniner.id || _needEmit) {// 将暗焦事件发布给所有组件
          this.options.forEachCommontens(function (ev) {
            if (ev.container.contains(_cacheConteniner) && (typeof ev.onDarkFocusChange === "function")) ev.onDarkFocusChange(_this, _cacheConteniner, isInit)
          })
        }
        this.setAttr(this.attrs.cacheWidget, _cacheConteniner.id)
        this.praveDarkContainerId = _cacheConteniner.id
      }
      /**焦点计算之前的生命周期 */
      this.onBeforeChangeFocus = function (curFocus, key) {
        var _sequenceItem = this.onSequenceAlgorithm(curFocus, key)
        if (_sequenceItem != null && (typeof _sequenceItem === "object")) return _sequenceItem
      }
      this.bindFocusBlur = function (curWidget, nextWidget, key) {
        var _fnStr = "";
        if (curWidget && this.container.contains(curWidget.container) && !this.container.contains(nextWidget.container)) {
          _fnStr = this.getAttr(this.attrs.onBlur)
        } else if ((!curWidget || !this.container.contains(curWidget.container)) && this.container.contains(nextWidget.container)) {
          _fnStr = this.getAttr(this.attrs.onFocus)
        }
        var _nextBoxBlur = null, params = { target: this, key: key, curWidget: curWidget, nextWidget: nextWidget }
        if (_fnStr && typeof _fnStr === "string") _nextBoxBlur = Utils.eval.onEval(_fnStr, params)
        if (_nextBoxBlur) return _nextBoxBlur
      }
      //焦点计算完成，即将完成跳转
      this.onWillChangeFocus = function (curWidget, _nextWidget, key) {
        if (!_nextWidget) return
        var _nextBlurFocus = this.bindFocusBlur(curWidget, _nextWidget, key)
        if (_nextBlurFocus) return _nextBlurFocus
        if (curWidget && curWidget.widgetBox && (curWidget.widgetBox.id !== this.id)) return
        if (curWidget && curWidget.widgetBox && _nextWidget.widgetBox && (curWidget.widgetBox.id === _nextWidget.widgetBox.id)) return
        var _nextBox = _baseFn.moveByAppoint(this, curWidget, _nextWidget, key)
        if (_nextBox) return _nextBox
      }
      this.onFocusChange = function (_now, _prave, _opt) {
        if (_now.widgetBox && _now.widgetBox.id === this.id) {
          this.container.classList.add(_defConfig.focusBoxClass)
        } else {
          this.container.classList.remove(_defConfig.focusBoxClass);
        }
      }
      this.onUpdate = function () {
        if (!this.cacheRect) this.rect = Utils.getRect(this.container)
        this.onSetDarkClass(true)
      }
      this.onCreated = function () {
        this.onSetDarkClass(true)
      }
      this.onDestroy = function () { }
    },
    /**
     * 焦点
     */
    [_defConfig.widgetClass]: function FocusWidget(container, options) {
      this.options = options || {}
      this.container = container
      this.name = _defConfig.widgetClass
      this.id = Utils.getDomId(this.container)
      this.rect = Utils.getRect(this.container)
      this.getAttr = this.container.getAttribute.bind(this.container)
      this.setAttr = this.container.setAttribute.bind(this.container)
      this.attrs = {
        onDarkFocus: "ondarkfocus",
        //焦点移出之前的函数，可返回焦点盒子(指定焦点移出时的下一个盒子，移出后的焦点必定是指定的下一个盒子内部的焦点)，或者true（控制不进行跳转）//(<div onleft="fn()"></div>)
        onLeft: "onleft", onRight: "onright", onUp: "onup", onDown: "ondown", onFocus: "onfocus", onBlur: "onblur",
        //指定盒子元素移出时聚焦的下一个的焦点盒子元素，多个盒子元素以,分割，优先查找第一个盒子元素的id，未找到时查找下一个
        goLeft: "f-goleft", goRight: "f-goright", goUp: "f-goup", goDown: "f-godown",
      }
      this.cacheRect = this.getAttr(this.attrs.cacheRect) === "true"
      // 初始化焦点信息
      this.init = function () {
        //找到该焦点在哪个盒子元素内部
        var _boxList = options.commontens ? options.commontens[_defConfig.boxClass] : []
        this.widgetBox = Utils.find(_boxList && _boxList.length ? _boxList : [], function (e) { return e.container.contains(container) });
        //移除默认焦点
        this.container.classList.remove(_defConfig.focusClass);
      }
      this.onBeforeChangeFocus = function (_curFocus, key) {
        //定向跳转
        var _nextWidget = _baseFn.moveByAppoint(this, _curFocus, undefined, key)
        if (_nextWidget) return _nextWidget
      }
      this.onWillChangeFocus = function (curWidget, nextWidget, key) {
        if (!nextWidget) {
          Utils.shakeElement(this.container, (key === _defConfig.keyEnum.LEFT || key === _defConfig.keyEnum.RIGHT) ? "X" : "Y")
          return
        }
        var _newFocus = null, _fnStr = "", params = { target: this, key: key, curWidget: curWidget, nextWidget: nextWidget }
        if (curWidget && curWidget.id === this.id) {
          _fnStr = this.getAttr(this.attrs.onBlur)
          if (_fnStr && typeof _fnStr === "string") _newFocus = Utils.eval.onEval(_fnStr, params)
        } else if (nextWidget && nextWidget.id === this.id) {
          _fnStr = this.getAttr(this.attrs.onFocus)
          if (_fnStr && typeof _fnStr === "string") _newFocus = Utils.eval.onEval(_fnStr, params)
        }
        return _newFocus
      }
      this.onFocusChange = function (ev, _prave, opt) {
        //设置焦点样式
        if (ev.id === this.id) {
          _prave.container.classList.remove(_defConfig.focusClass);
          ev.container.classList.add(_defConfig.focusClass)
          if (this.widgetBox) this.setDarkFocus(opt.isInit)
        }
      }
      this.setDarkFocus = function (_isInit, needEmit) {
        if (this.widgetBox) this.widgetBox.setDarkFocus(this, _isInit, needEmit)
      }
      this.onDarkFocusChange = function (box, ctx, isInit) {
        if (ctx.id !== this.id) return
        Utils.eval.onEval(this.getAttr(this.attrs.onDarkFocus), { target: this, widgetBox: box, isInit: isInit, curWidget: this.options.focusItem })
      }
      //滚动组件滚动时，更新rect信息
      this.onScrollMove = function (scrollBox, moveNo) {
        this.rect = _baseFn.getRectInScroll(this.rect, scrollBox.scrollDir, moveNo)
      }
      this.onUpdate = function () {
        if (!this.cacheRect) this.rect = Utils.getRect(this.container)
      }
      this.onCreated = function () { }
      this.onDestroy = function () { }
      this.init()
    },
    /**
     * 文字滚动
     */
    [_defConfig.marqueeClass]: function FocusMarquee(container) {
      this.container = container
      this.name = _defConfig.widgetClass
      this.id = Utils.getDomId(this.container)
      this.getAttr = this.container.getAttribute.bind(this.container)
      this.setAttr = this.container.setAttribute.bind(this.container)
      this.attrs = {
        //焦点移出之前的函数，可返回焦点盒子(指定焦点移出时的下一个盒子，移出后的焦点必定是指定的下一个盒子内部的焦点)，或者true（控制不进行跳转）//(<div onleft="fn()"></div>)
        onLeft: "onleft", onRight: "onright", onUp: "onup", onDown: "ondown", onFocus: "onfocus", onBlur: "onblur",
        //指定盒子元素移出时聚焦的下一个的焦点盒子元素，多个盒子元素以,分割，优先查找第一个盒子元素的id，未找到时查找下一个
        goLeft: "f-goleft", goRight: "f-goright", goUp: "f-goup", goDown: "f-godown",
      }
      this.bindFocusBlur = function (curWidget, nextWidget, key) {
        var _fnStr = "";
        if (curWidget && curWidget.container.contains(this.container) && !nextWidget.container.contains(this.container)) {
          _fnStr = this.getAttr(this.attrs.onBlur)
        } else if ((!curWidget || !curWidget.container.contains(this.container)) && nextWidget.container.contains(this.container)) {
          _fnStr = this.getAttr(this.attrs.onFocus)
        }
        var _nextBoxBlur = null, params = { target: this, key: key, curWidget: curWidget, nextWidget: nextWidget }
        if (_fnStr && typeof _fnStr === "string") _nextBoxBlur = Utils.eval.onEval(_fnStr, params)
        if (_nextBoxBlur) return _nextBoxBlur
      }
      //焦点计算完成，即将完成跳转
      this.onWillChangeFocus = function (curWidget, _nextWidget, key) {
        if (!_nextWidget) return
        var _nextBlurFocus = this.bindFocusBlur(curWidget, _nextWidget, key)
        if (_nextBlurFocus) return _nextBlurFocus
        if (curWidget && !curWidget.container.contains(this.container)) return
        var _nextBox = _baseFn.moveByAppoint(this, curWidget, _nextWidget, key)
        if (_nextBox) return _nextBox
      }
      this.onFocusChange = function (now, prave) {
        if (prave && now !== prave) Utils.marquee.restore(prave.id)
        if (now === this.container || now.container.contains(this.container)) {
          Utils.nextTick(function () {
            Utils.marquee.start(now.id)
          })
        }
      }
      this.onCreated = function () {
        Utils.marquee.restore(this.id)
      }
      this.onDestroy = function () {
        Utils.marquee.restore(this.id)
      }
    },
    /**  滚动居中区域 */
    [_defConfig.scrollClass]: function FocusScroll(container, options) {
      this.options = options || {}
      this.container = container
      this.name = _defConfig.scrollClass
      this.id = Utils.getDomId(this.container)
      this.getAttr = this.container.getAttribute.bind(this.container)
      this.setAttr = this.container.setAttribute.bind(this.container)
      this.attrs = {
        scroll: "f-scroll",//滚动方向X/Y。(<div f-scroll="X"></div>)
        offsetNum: "f-offset",//滚动居中，滚动居左或者居右的边距，需配合f-postion使用。(<div f-offset="center"></div>/<div f-offset="100"></div>)
        centerPostion: "f-postion",//滚动居中，滚动居左或者居右，需配合f-offset使用。(<div f-offset="postion"></div>/<div f-offset="left"></div>/<div f-offset="right"></div>)
      }
      this.scrollDir = this.getAttr(this.attrs.scroll);
      this.scrollTimer = null
      //内部滚动区域
      this.scrollContent = null
      //内容滚动的区域div
      this.contentClass = _defConfig.scrollClass + "Content"
      //滚动居中div，用于包裹焦点元素，或者一整个居中区域
      this.itemClass = _defConfig.scrollClass + "Item"
      this.init = function () {
        this.scrollContent = Utils.$class(this.contentClass, this.container)[0]
        if (!this.scrollContent) return console.log("滚动组件内部必须创建-" + this.contentClass);
      }
      this.onFocusChange = function (now, prave, opt) {
        var _this = this
        if (this.container.contains(prave.container) && !this.container.contains(now.container) && now.id === prave.id) { } else if (this.container.contains(now.container)) {
          Utils.nextTick(function () {
            _this.scrollToWidget(now, !opt.isInit)
          })
        }
      }
      this.onDarkFocusChange = function (_, darkConteniner, isInit) {
        var _this = this
        Utils.nextTick(function () {
          var _widget = Utils.find(_this.options.commontens[_defConfig.widgetClass] || [], function (ev) {
            return ev.id === darkConteniner.id
          })
          if (_widget !== _this.options.focusItem) {
            var _isScrollBox = Utils.$class(_defConfig.scrollClass, _this.container).length > 0
            var _isVirtualBox = Utils.$class(_defConfig.virtualClass, _this.container).length > 0
            if (_isScrollBox || _isVirtualBox || !_this.container.contains(darkConteniner)) return
            _this.scrollToWidget(_widget, !isInit)
          }
        })
      }
      this.scrollToWidget = function (widget, isAnimate) {
        this.cacheScrollAnimate()
        if (!this.scrollContent) return
        var _this = this
        var _scrollItem = null
        if (!this.container.contains(widget.container)) return
        _scrollItem = Utils.find(Utils.$class(this.itemClass, this.container), function (scrollItem) {
          return scrollItem.contains(widget.container)
        })
        if (!_scrollItem) return
        var _dir = this.scrollDir
        var _moveInfo = _baseFn.getScrollNo(this, _scrollItem, _dir)
        if (_moveInfo.number === _moveInfo.oldNumber) return
        if (isAnimate == false) {
          this.scrollContent.style[_dir === "X" ? "left" : 'top'] = _moveInfo.number + "px"
        } else {
          this.scrollTimer = Utils.animate(this.scrollContent, _moveInfo.number, _defConfig.animateTimeout, _dir === "X" ? "left" : 'top');
        }
        var _isScrollBox = Utils.$class(_defConfig.scrollClass, this.container).length > 0
        //是否刷新内部元素的位置信息
        if (!_isScrollBox) {
          //将滚动事件与滚动距离向内部组件进行播报
          this.options.forEachCommontens(function (ele) {
            if (!_this.container.contains(ele.container) || _this.container === ele.container) return
            if (ele.onScrollMove) ele.onScrollMove(_this, _moveInfo.number)
          })
        }
      }
      this.cacheScrollAnimate = function () {
        if (this.scrollTimer) {
          if (this.scrollTimer.animateId) Utils.cancelAnimationFrame(this.scrollTimer.animateId)
          if (this.scrollTimer.finishImmediately) this.scrollTimer.finishImmediately()
        }
        this.scrollTimer = null
      }
      this.onCreated = function () {
        this.cacheScrollAnimate()
      }
      this.onDestroy = function () {
        this.cacheScrollAnimate()
      }
      this.init()
    },
    /** 虚拟列表+滚动居中，主要为了提升长列表的性能，使盒子不卡顿，因为用法不如FocusScroll组件方便，所以两者都有存在的必要 */
    [_defConfig.virtualClass]: function FocusVirtual(container, options) {
      this.options = options || {}
      this.container = container
      this.name = _defConfig.virtualClass
      this.id = Utils.getDomId(this.container)
      this.getAttr = this.container.getAttribute.bind(this.container)
      this.setAttr = this.container.setAttribute.bind(this.container)
      this.attrs = {
        //函数，返回参数{html:string,focuspos:number, focusdomid:string}
        onCreateItem: "oncreateitem",//创建单项数据节点。(<div oncreateitem="create()"></div>)
        curIndex: "f-curindex",//开始计数的项，默认0，比如配置为10，那么oncreateitem则从10开始渲染数据，直至渲染到宽度超过滚动区域宽度+（f-cachesize）配置的宽度。(<div f-curindex="10"></div>)
        cacheSize: "f-cachesize",//超过滚动区域宽度后需要再渲染多少宽度。(<div f-cachesize="300"></div>)
        totalSize: "f-totalsize",//数据总数。(<div f-totalsize="10000"></div>)
        scroll: "f-scroll",//滚动方向X/Y。(<div f-scroll="X"></div>)
        offsetNum: "f-offset",//滚动居中，滚动居左或者居右的边距，需配合f-postion使用。(<div f-offset="center"></div>/<div f-offset="100"></div>)
        centerPostion: "f-postion",//滚动居中，滚动居左或者居右，需配合f-offset使用。(<div f-offset="postion"></div>/<div f-offset="left"></div>/<div f-offset="right"></div>)
      }
      this.scrollDir = this.getAttr(this.attrs.scroll);
      this.scrollTimer = null
      //内容滚动的区域div
      this.contentClass = _defConfig.virtualClass + "Content" + this.id
      //滚动居中div，用于包裹焦点元素，或者一整个居中区域
      this.itemClass = _defConfig.virtualClass + "Item" + this.id
      //内部滚动区域
      this.scrollContent = null
      this.init = function () {
        //创建内部滚动区域
        this.container.innerHTML = '<div class="' + this.contentClass + '" style="position:absolute;left:0;top:0;"></div>'
        this.scrollContent = Utils.$class(this.contentClass)[0];
        if (!this.scrollContent) return
        if (this.scrollDir === 'X') {
          this.scrollContent.style["white-space"] = 'nowrap'
        }
        this.childItemController()
      }
      this.emitDarkFocus = function (item) {
        var _this = this
        if (_this._widgetBox) {
          Utils.nextTick(function () {
            var _widgetInItem = null
            options.forEachCommontens(function (ev) {
              if (ev.name === _defConfig.widgetClass && item.contains(ev.container)) _widgetInItem = ev
            })
            if (!_widgetInItem) return
            if (_this._widgetBox.getAttr(_this._widgetBox.attrs.cacheWidget) === _widgetInItem.id) {
              _widgetInItem.setDarkFocus(undefined, true)
            }
          })
        }
      }
      //创建内容
      this._createItem = function (index, pos, itemOld) {
        if (itemOld) {
          this.emitDarkFocus(itemOld)
          return Utils.getRect(itemOld)
        }
        var item = document.createElement('div');
        item.setAttribute("f-index", index)
        item.className = this.itemClass;
        if (this.scrollDir === 'X') item.style.display = 'inline-block'
        var _itemContent = Utils.eval.onEval(this.getAttr(this.attrs.onCreateItem), index)
        if (!_itemContent) return
        if (_itemContent.html) {
          item.innerHTML = _itemContent.html
        } else {
          item.textContent = ""
        }
        if (_itemContent.focuspos) {
          item.setAttribute("f-focuspos", _itemContent.focuspos)
        }
        if (_itemContent.focusdomid) {
          item.setAttribute("f-focusdomid", _itemContent.focusdomid)
        }
        if (pos === "before") {
          this.scrollContent.insertBefore(item, this.scrollContent.firstChild);
        } else {
          this.scrollContent.appendChild(item)
        }
        this.emitDarkFocus(item)
        return Utils.getRect(item)
      }
      this.findwidgetBox = function () {
        var _box = null, _this = this
        options.forEachCommontens(function (ev) {
          if (ev.name === _defConfig.boxClass && ev.container.contains(_this.container)) _box = ev
        })
        this._widgetBox = _box
      }
      //子节点控制器-创建基于视口宽度的子节点内容
      this.childItemController = function () {
        var _curIndex = parseInt(this.getAttr(this.attrs.curIndex)) || 0
        var _startIndex = _curIndex
        var _endIndex = _curIndex
        //超出当前屏幕后需要缓存的距离，左右各增加默认300的宽度渲染数据
        var _cacheSize = parseInt(this.getAttr(this.attrs.cacheSize)) || 300
        if (!this.scrollContent) return
        var _this = this
        var _totalNum = this.getAttr(this.attrs.totalSize), _dir = this.scrollDir
        if (_totalNum <= 0) return
        var _boxRect = Utils.getRect(this.container)
        var _boxLen = _dir === 'X' ? _boxRect.width : _boxRect.height
        var _itemLens = 0
        for (var i = 0; i < _totalNum; i++) {
          var _itemList = Utils.$class(this.itemClass, this.scrollContent)
          var _rectItm = { width: 0, height: 0 }
          if (_startIndex === _curIndex && _endIndex === _curIndex) {
            _rectItm = this._createItem(_curIndex, "after", Utils.find(_itemList, function (e) { return e.getAttribute("f-index") == _curIndex }))
            _itemLens += (_dir === 'X' ? _rectItm.width : _rectItm.height)
          }
          var _hasMore = false
          if (_itemLens > (_boxLen + _cacheSize)) break;
          if (_startIndex > 0) {
            _startIndex--
            _rectItm = this._createItem(_startIndex, "before", Utils.find(_itemList, function (e) { return e.getAttribute("f-index") == _startIndex }))
            _itemLens += (_dir === 'X' ? _rectItm.width : _rectItm.height)
            _hasMore = true
          }
          if (_endIndex < _totalNum) {
            _endIndex++
            _rectItm = this._createItem(_endIndex, "after", Utils.find(_itemList, function (e) { return e.getAttribute("f-index") == _endIndex }))
            _itemLens += (_dir === 'X' ? _rectItm.width : _rectItm.height)
            _hasMore = true
          }
          if (!_hasMore) break;
        }
        if (_startIndex != _curIndex || _endIndex != _curIndex) {
          //移除不可见元素
          Utils.forEach(Utils.$class(this.itemClass, this.scrollContent), function (e) {
            var _index = parseInt(e.getAttribute("f-index"))
            if (!isNaN(_index) && !(_index >= _startIndex && _index <= _endIndex)) {
              _this.scrollContent.removeChild(e);
            }
          })
        }
        //创建完成后需要触发组件刷新动作
        Utils.nextTick(function () {
          _this.options.updateCommontens()
        })
      }
      this.onFocusChange = function (now, prave, opt) {
        var _this = this
        var _item = Utils.find(Utils.$class(this.itemClass, this.scrollContent), function (e) { return e.contains(now.container) })
        if (_item) {
          var _index = _item.getAttribute("f-index")
          if (_index) this.setAttr(this.attrs.curIndex, _index)
        }
        if (this.container.contains(prave.container) && !this.container.contains(now.container) && now.id === prave.id) { } else if (this.container.contains(now.container)) {
          Utils.nextTick(function () {
            _this.scrollToWidget(now.container, !opt.isInit)
          })
        }
      }
      this.onDarkFocusChange = function (_, darkConteniner, isInit) {
        var _isScrollBox = Utils.$class(_defConfig.scrollClass, this.container).length > 0
        if (_isScrollBox || !this.container.contains(darkConteniner)) return
        var _this = this
        var _item = Utils.find(Utils.$class(this.itemClass, this.scrollContent), function (e) { return e.contains(darkConteniner) })
        if (_item) {
          var _index = _item.getAttribute("f-index")
          if (_index) this.setAttr(this.attrs.curIndex, _index)
        }
        Utils.nextTick(function () {
          var _widget = Utils.find(_this.options.commontens[_defConfig.widgetClass] || [], function (ev) {
            return ev.id === darkConteniner.id
          })
          if (_widget !== _this.options.focusItem) {
            _this.scrollToWidget(_widget ? _widget.container : darkConteniner, !isInit)
          }
        })
      }
      this.scrollToWidget = function (_container, isAnimate) {
        this.cacheScrollAnimate()
        if (!this.scrollContent) return
        var _scrollItem = null, _dir = this.scrollDir
        if (!this.container.contains(_container)) return
        _scrollItem = Utils.find(Utils.$class(this.itemClass, this.container), function (scrollItem) {
          return scrollItem.contains(_container)
        })
        if (!_scrollItem) return
        var _moveInfo = _baseFn.getScrollNo(this, _scrollItem, _dir)
        if (_moveInfo.number === _moveInfo.oldNumber) return
        var _this = this
        if (isAnimate == false) {
          this.childItemController()
          resetCenter()
        } else {
          this.scrollTimer = Utils.animate(this.scrollContent, _moveInfo.number, _defConfig.animateTimeout, _dir === "X" ? "left" : 'top', function () {
            _this.scrollTimer = null
            _this.childItemController()
            resetCenter()
          });
        }
        function resetCenter() {
          var _newScrollItem = Utils.find(Utils.$class(_this.itemClass, _this.container), function (scrollItem) {
            return scrollItem.contains(_container)
          })
          if (!_newScrollItem) return
          var _moveInfo1 = _baseFn.getScrollNo(_this, _newScrollItem, _dir)
          _this.scrollContent.style[_dir === "X" ? "left" : 'top'] = _moveInfo1.number + "px"
        }
      }
      this.cacheScrollAnimate = function () {
        if (this.scrollTimer) {
          if (this.scrollTimer.animateId) Utils.cancelAnimationFrame(this.scrollTimer.animateId)
          if (this.scrollTimer.finishImmediately) this.scrollTimer.finishImmediately()
        }
        this.scrollTimer = null
      }
      this.onCreated = function () {
        this.cacheScrollAnimate()
        this.findwidgetBox()
        this.init()
      }
      this.onDestroy = function () {
        this.cacheScrollAnimate()
      }
    },
  }
  // 焦点框架核心 ----------------------------------------------
  function FocusFrame(_id, params) {
    //默认配置参数
    params = params || { config: {}, commontens: {} }
    this.container = Utils.$(_id);
    this.Utils = Utils
    _defConfig = Utils.objConcat(_defConfig, params.config || {})
    this.config = {
      useKeyDown: params.useKeyDown == null ? true : params.useKeyDown,//是否使用内置的焦点监听
      Commontens: Utils.objConcat(_DefCommontens, params.commontens || {}),//解析传入的组件
    };
    this.attrs = {}
    this.state = {
      switchList: [],//主焦点框架
      popupList: [],//弹窗列表
      keyDownFns: {},//绑定的监听的函数
      locked: false,//焦点锁-这里锁住所有焦点
    };
    this.init();
    this.onListenKeyDown();
    Utils.eventListener(this.container, 'unload', this.onUnLoad);
  }
  FocusFrame.prototype = {
    init: function (_container) {
      if (_container) this.container = _container//当前页面的dom信息
      if (!this.container) throw new Error('必须提供容器元素');
      var _this = this
      //获取焦点框架列表
      Utils.forEach(Utils.$class(_defConfig.switchClass, this.container), function (_ele) {
        var _switchItem = Utils.find(_this.state.switchList, function (_el) { return _el.container === _ele });
        if (_switchItem && _switchItem.container === _ele) {
          _switchItem.init();
        } else {
          _this.state.switchList.push(_this.createSwitch(_ele));
        }
      })
    },
    onUnLoad: function () {
      Utils.forEach(this.state.switchList, function (ev) {
        if (ev.onDestroy) ev.onDestroy()
      })
      Utils.forObjEach(Utils.marquee.marqueeTimer, function (_, v) {
        Utils.cancelAnimationFrame(v)
      })
    },
    onSwitchDestroy: function (ev) {
      if (ev && ev.onDestroy) ev.onDestroy()
    },
    /**查找焦点框架*/
    findSwitch: function (ele) {
      if (!ele) return null;
      var _item = Utils.find(this.state.switchList, function (ev) { return (typeof ele === "string" ? ev.container.id : ev.container) === ele });
      return _item;
    },
    createSwitch: function (_ele) {
      return new FocusSwitch({ container: _ele, decodeCommontens: this.config.Commontens })
    },
    /** 操作弹窗的显示状态 */
    onPopup: function (_ele, show) {
      if (typeof _ele === "string") _ele = Utils.$(_ele);
      if (!_ele) return
      if (_ele.classList && _ele.classList.contains(_defConfig.popupClass)) {
        _ele.style.display = show ? "block" : "none";
        var _popupIdx = Utils.findIndex(this.state.popupList, function (ev) { return ev.container === _ele }),
          _switchIdx = Utils.findIndex(this.state.switchList, function (ev) { return ev.container === _ele });
        if (!show) {
          if (_popupIdx >= 0) {
            this.state.popupList.splice(_popupIdx, 1);
          }
          if (_switchIdx >= 0) {
            this.onSwitchDestroy(this.state.switchList[_switchIdx])
            this.state.switchList.splice(_switchIdx, 1);
          }
        } else {
          if (_popupIdx >= 0) {
            this.state.popupList[_popupIdx].show = true;
          } else {
            this.state.popupList.push({ container: _ele, show: true });
          }
          if (_switchIdx < 0) {
            this.state.switchList.push(this.createSwitch(_ele));
          }
        }
      } else {
        console.log("传入的不是弹窗元素");
      }
    },
    /**键盘事件监听*/
    onEmitKeyDown: function (key, fn) {
      if (typeof key !== "string" || typeof fn !== "function") return;
      this.state.keyDownFns[key] = fn;
    },
    /**取消键盘事件监听*/
    onRemoveKeyDown: function (key) {
      if (typeof key !== "string") return;
      delete this.state.keyDownFns[key];
    },
    /**清空键盘事件监听 */
    onClearKeyDown: function () {
      this.state.keyDownFns = {};
    },
    /**焦点锁*/
    onLock: function (ev) {
      this.state.locked = !!ev;
    },
    /**键盘事件分发给焦点框架*/
    distributeKeyDown: function (_keyCode) {
      if (this.keyDownTimer != null) return
      var _this = this;
      if (_this.state.locked) return;
      var _boardKey = Utils.getKeyValue(_keyCode);
      if (_boardKey == null) return
      for (var fnsKey in _this.state.keyDownFns) {
        var _fn = _this.state.keyDownFns[fnsKey];
        if (typeof _fn === "function") {
          _fn(_boardKey);
        }
      }
      Utils.forEach(Utils.map(_this.state.switchList, function(e){ return e }), function (_switchItem) {
        var _popupIdx = Utils.findIndex(_this.state.popupList, function (_popupItem) { return _popupItem.container === _switchItem.container });
        var isPopup = _switchItem.container.classList && _switchItem.container.classList.contains(_defConfig.popupClass);
        if ((isPopup && _popupIdx > -1 && _popupIdx === _this.state.popupList.length - 1 && _this.state.popupList[_popupIdx].show) || (!isPopup && _this.state.popupList.length === 0)) {
          _switchItem.handleKeyDown({ keyCode: _keyCode, keyValue: _boardKey });
        }
      })
      this.keyDownTimer = setTimeout(function () { clearTimeout(_this.keyDownTimer); _this.keyDownTimer = null }, _defConfig.keyDownTimeout);
    },
    /** 监听键盘事件分发给焦点框架*/
    onListenKeyDown: function () {
      if (this.config.useKeyDown === false) return
      var _this = this;
      Utils.eventListener(window, "keydown", function (ev) {
        _this.distributeKeyDown(ev.keyCode)
      })
    },
  }
  //核心焦点逻辑
  function FocusSwitch(params) {
    params = params || {}
    this.container = params.container
    this.decodeCommontens = params.decodeCommontens
    this.getAttr = this.container.getAttribute.bind(this.container)
    this.setAttr = this.container.setAttribute.bind(this.container)
    this.tryMove = false//焦点重试暂存
    this.attrs = {
      focusId: "f-focusid",
      focusChange: "onfocuschange",
    }
    this.focusItem = null//当前选中项
    this.locked = false//焦点锁
    this.isInitCommonents = false //是否通过组件初始化
    //组件列表
    this.commontens = {}
    this.init()
  }

  FocusSwitch.prototype = {
    init: function () {
      this.initCommonents()
      this.observeDOM = Utils.observeDOMChanges(function () { this.initCommonents() }.bind(this), this.container)
      this.onSwitchFocusChange()
    },
    onChangeFocus: function (_id) {
      if (typeof _id !== "string") return
      var _widget = Utils.find(this.commontens[_defConfig.widgetClass], function (e) { return e.id === _id })
      if (!_widget) return
      var _cur = this.focusItem
      this.onSetFocus(_widget)
      this.forEachCommontens(function (ele) {
        if (ele && ele.onFocusChange) {
          ele.onFocusChange(_widget, _cur, { isInit: false })
        }
      })
    },
    onSetFocus: function (_item) {
      this.focusItem = _item
      this.setAttr(this.attrs.focusId, _item.id)
    },
    onSwitchFocusChange: function () {
      var _focusChange = this.getAttr(this.attrs.focusChange)
      if (_focusChange) {
        Utils.eval.onEval(_focusChange, {
          target: this,
          focusItem: this.focusItem,
        })
      }
    },
    onSetDarkFocus: function (_id) {
      if (typeof _id !== "string") return
      var _widget = Utils.find(this.commontens[_defConfig.widgetClass], function (e) { return e.id === _id })
      if (!_widget || !_widget.setDarkFocus) return
      _widget.setDarkFocus()
    },
    setDarkFocusById: function (_id) { return this.onSetDarkFocus(_id) },
    onCreated: function (_isInit) {
      var _this = this
      this.forEachCommontens(function (ele) {
        if (ele.isFirst == false) {
          if (ele && ele.onUpdate) ele.onUpdate(_this.focusItem)
          return
        }
        if (ele && ele.onCreated) {
          ele.onCreated(_this.focusItem)
        }
        if (ele && ele.onFocusChange && _this.focusItem) {//创建时，如果当前焦点元素还未初始化，则不需要触发onFocusChange
          ele.onFocusChange(_this.focusItem, _this.focusItem, { isInit: _isInit })
        }
      })
    },
    onDestroy: function () {
      var _this = this
      this.forEachCommontens(function (ele) {
        if (ele && ele.onDestroy) {
          ele.onDestroy(_this.focusItem)
        }
      })
      if (this.observeDOM) this.observeDOM.disconnect()
    },
    /**焦点锁*/
    onLock: function (ev) {
      this.locked = !!ev;
    },
    forEachCommontens: function (callback) {
      Utils.forObjEach(this.commontens, function (_, val) {
        Utils.forEach(val, callback)
      })
    },
    //更新组件列表
    updateCommontens: function (opt) {
      var _this = this
      opt = opt || {}
      Utils.forObjEach(_this.decodeCommontens, function (key) {
        var _domList = Utils.$class(key, _this.container)
        var _components = Utils.map(_domList, function (ev) {
          var _oldWidget = Utils.find(_this.commontens[key] || [], function (ele) { return ele.container === ev })
          if (_oldWidget) {
            if (!opt.isInit) _oldWidget.isFirst = false;
            return _oldWidget
          }
          var _newComment = new _this.decodeCommontens[key](ev, _this)
          if (!_this.isInitCommonents && _newComment.onCreated) _newComment.onCreated()//刷新组件列表时新增的组件，需要单独处理onCreated事件
          return _newComment
        })
        Utils.forEach(_this.commontens[key] || [], function (ev) {
          var _oldWidget = Utils.find(_components, function (ele) { return ele.container === ev.container })
          if (!_oldWidget && ev.onDestroy) ev.onDestroy()
        })
        _this.commontens[key] = _components
      })
    },
    initCommonents: function () {
      this.isInitCommonents = true
      var _isInit = !this.focusItem
      this.updateCommontens({ isInit: _isInit })
      var _defFocus = null, _id = this.focusItem ? this.focusItem.id : this.getAttr(this.attrs.focusId)
      if (_id) _defFocus = Utils.find(this.commontens[_defConfig.widgetClass], function (e) { return e.id === _id })
      if (!_defFocus) _defFocus = this.commontens[_defConfig.widgetClass][0]
      if (_defFocus) {
        var _willNextItem = this.bindChangeFocus("init", "onWillChangeFocus", _defFocus)
        this.onSetFocus(_willNextItem || _defFocus)
      }
      this.onCreated(_isInit)
      this.isInitCommonents = false
    },
    upDataWidget: function () { return this.initCommonents() },//兼容
    /**为所有组件绑定并执行函数:onenter, onback, onhome, ondel, onmenu, onnumber*/
    onBindFunction: function (_keyValue) {
      var _fnEnum = {
        [_defConfig.keyEnum.ENTER]: "onenter",
        [_defConfig.keyEnum.BACK]: "onback",
        [_defConfig.keyEnum.HOME]: "onhome",
        [_defConfig.keyEnum.DEL]: "ondel",
        [_defConfig.keyEnum.MENU]: "onmenu",
      }
      var _fnArryName = _fnEnum[_keyValue]
      if (typeof _keyValue === "number") _fnArryName = "onnumber"
      if (!_fnArryName || (typeof _fnArryName !== "string")) return
      var _curFocus = this.focusItem
      var onEmitFn = function (ev) {
        if (_curFocus.container && (!ev.container.contains(_curFocus.container)) && ev.container !== _curFocus.container) return
        var _attrFn = ev.getAttr ? ev.getAttr(_fnArryName) : ""
        var _params = { target: ev, key: _keyValue, curWidget: _curFocus }
        if (_attrFn) Utils.eval.onEval(_attrFn, _params)
        if (typeof ev[_fnArryName] === "function") ev[_fnArryName](_params)
      }
      onEmitFn(this)
      this.forEachCommontens(onEmitFn)
    },
    handleKeyDown: function (ev) {
      if (this.locked) return
      console.time()
      this.tryMove = false
      this.onBindFunction(ev.keyValue)
      this.onMove(ev.keyValue)
      console.timeEnd()
    },
    //给组件绑定焦点移动的生命周期
    bindChangeFocus: function (_keyval, bindFn, nextWidget) {
      var _this = this;
      var _cur = this.focusItem, _item = null
      var _curList = [], _nextList = []
      this.forEachCommontens(function (e) {
        if (_cur && (e.container.contains(_cur.container) || _cur.container.contains(e.container))) {
          _curList.push(e)
        } else if (nextWidget && (e.container.contains(nextWidget.container) || nextWidget.container.contains(e.container))) {
          _nextList.push(e)
        }
      })
      function evalBindFn(_l) {
        Utils.find(_l, function (e) {
          if (!e) return null
          var _backInfo = null
          if (typeof e[bindFn] === "function") {
            if (bindFn === "onWillChangeFocus") {
              _backInfo = e[bindFn](_cur, nextWidget, _keyval)
            } else {
              _backInfo = e[bindFn](_cur, _keyval)
            }
          }
          if (typeof _backInfo === "string") {
            var _widgetItm = Utils.find(_this.commontens[_defConfig.widgetClass], function (e) { return e.id === _backInfo })
            if (!_widgetItm) _widgetItm = Utils.find(_this.commontens[_defConfig.boxClass], function (e) { return e.id === _backInfo })
            //如果返回数据是焦点元素或者盒子元素，则直接返回
            if (_widgetItm && (_widgetItm.name === _defConfig.widgetClass || _widgetItm.name === _defConfig.boxClass)) {
              _item = _widgetItm
            }
          } else if ((_backInfo != null) && (typeof _backInfo === "object") && (_backInfo.name === _defConfig.widgetClass || _backInfo.name === _defConfig.boxClass)) {
            _item = _backInfo
          } else if (_backInfo === true) {
            _item = true
          }
          return _item
        })
      }
      evalBindFn(_curList)
      if (_item) return _item
      evalBindFn(_nextList)
      return _item
    },
    onMove: function (_keyValue) {
      var _moveList = [_defConfig.keyEnum.LEFT, _defConfig.keyEnum.RIGHT, _defConfig.keyEnum.UP, _defConfig.keyEnum.DOWN]
      if (!Utils.find(_moveList, function (e) { return e === _keyValue })) return
      var _curItem = this.focusItem, _nextItem = null;
      _nextItem = this.bindChangeFocus(_keyValue, "onBeforeChangeFocus")
      if (_nextItem === true) return
      if (!_nextItem || (_nextItem.name !== _defConfig.widgetClass)) _nextItem = this.onFindWidgetByMove(_keyValue)
      if (!_nextItem || (_nextItem && (_nextItem.name === _defConfig.widgetClass))) {
        var _willNextItem = this.bindChangeFocus(_keyValue, "onWillChangeFocus", _nextItem)
        if (_willNextItem && (_willNextItem.name === _defConfig.boxClass)) {
          var _newNextItem = this.onFindWidgetByMove(_keyValue, _willNextItem)
          if (_newNextItem && (_newNextItem.name === _defConfig.widgetClass)) _nextItem = _newNextItem
        } else if (_willNextItem && (_willNextItem.name === _defConfig.widgetClass)) {
          _nextItem = _willNextItem
        }
      }
      if (!_nextItem || (_nextItem.name !== _defConfig.widgetClass)) {
        if (!this.tryMove) {
          this.tryMove = true
          this.updateCommontens()
          this.onMove(_keyValue)
        }
        return
      }
      this.onSetFocus(_nextItem)
      this.onSwitchFocusChange()
      this.forEachCommontens(function (ele) {
        if (ele && ele.onFocusChange) {
          ele.onFocusChange(_nextItem, _curItem, { isInit: false, keyValue: _keyValue })
        }
      })
    },
    onFindWidgetByMove: function (_key, defaultItem) {
      var _focusItem = this.focusItem
      if (!_focusItem) return
      var _nextFocusItem = null, _item = null;
      var _widgetList = this.commontens[_defConfig.widgetClass]
      //用于指定盒子跳转
      if (defaultItem && defaultItem.name === _defConfig.boxClass) {
        _item = defaultItem
      } else {
        var _list = Utils.filter(_widgetList, function (el) { return !el.widgetBox || el.widgetBox === _focusItem.widgetBox; });//先查找出不在box中的焦点
        Utils.forEach(this.commontens[_defConfig.boxClass], function (ev) {
          if (ev === _focusItem.widgetBox) return
          _list.push(ev);
        })
        _item = this.onShadowAlgorithm(_focusItem, _list, _key);
        if (!_item) _item = this.onAreaAlgorithm(_focusItem, _list, _key);
        if (!_item) return;
      }
      if (_item.name === _defConfig.boxClass) {
        //查看是否有缓存方向的配置项
        _nextFocusItem = _item.getCacheWidget(_key)
        if (!_nextFocusItem) {
          var widigetListInBox = Utils.filter(_widgetList, function (_el) {
            return (_el.widgetBox && !Utils.isEleHide(_el.container)) ? _el.widgetBox.id === _item.container.id : null;
          });
          _nextFocusItem = this.onShadowAlgorithm(_focusItem, widigetListInBox, _key);
          if (!_nextFocusItem) {
            _nextFocusItem = this.onAreaAlgorithm(_focusItem, widigetListInBox, _key);
          }
        }
      } else {
        _nextFocusItem = Utils.find(_widgetList, function (_el) {
          return _el.container === _item.container;
        });
      }
      return _nextFocusItem
    },
    /**阴影算法 */
    onShadowAlgorithm: function (widgetItem, widgetList, direction) {
      var currentWidget = widgetItem.container, currentRect = widgetItem.rect, _select = { item: null, }, dis = Infinity, tempDis, xtItemWidget = [];
      for (var i = 0; i < widgetList.length; i++) {
        var tempWidget = widgetList[i].container;
        if (widgetList[i].name === _defConfig.boxClass && !Utils.find(Utils.$class(_defConfig.widgetClass, tempWidget), function (e) { return !Utils.isEleHide(e) })) continue;
        if (tempWidget === currentWidget) continue;
        var tempWidgetRect = widgetList[i].rect;
        if (tempWidgetRect.height == 0 || tempWidgetRect.width == 0) continue;
        if (direction === _defConfig.keyEnum.LEFT && tempWidgetRect.right < currentRect.centerX && tempWidgetRect.left < currentRect.left && tempWidgetRect.top < currentRect.bottom && tempWidgetRect.bottom > currentRect.top) {
          tempDis = currentRect.right - tempWidgetRect.right;
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          } else if (tempDis === dis) {
            xtItemWidget.push({ item: widgetList[i], dis: tempDis })
          }
        } else if (direction === _defConfig.keyEnum.RIGHT && tempWidgetRect.left > currentRect.centerX && tempWidgetRect.right > currentRect.right && tempWidgetRect.top < currentRect.bottom && tempWidgetRect.bottom > currentRect.top) {
          tempDis = tempWidgetRect.left - currentRect.left;
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          } else if (tempDis === dis) {
            xtItemWidget.push({ item: widgetList[i], dis: tempDis })
          }
        } else if (direction === _defConfig.keyEnum.UP && tempWidgetRect.bottom < currentRect.centerY && tempWidgetRect.top < currentRect.top && tempWidgetRect.left < currentRect.right && tempWidgetRect.right > currentRect.left) {
          tempDis = currentRect.bottom - tempWidgetRect.bottom;
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          } else if (tempDis === dis) {
            xtItemWidget.push({ item: widgetList[i], dis: tempDis })
          }
        } else if (direction === _defConfig.keyEnum.DOWN && tempWidgetRect.top > currentRect.centerY && tempWidgetRect.bottom > currentRect.bottom && tempWidgetRect.left < currentRect.right && tempWidgetRect.right > currentRect.left) {
          tempDis = tempWidgetRect.top - currentRect.top;
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          } else if (tempDis === dis) {
            xtItemWidget.push({ item: widgetList[i], dis: tempDis })
          }
        }
      }
      function calcDis(p1, p2) {
        var dx = p2.centerX - p1.centerX;
        var dy = p2.centerY - p1.centerY;
        return Math.sqrt(dx * dx + dy * dy);
      }
      xtItemWidget.push({ item: _select.item, dis: dis })
      var _sqrtDis = Infinity
      Utils.forEach(xtItemWidget, function (val) {
        if (!val.item) return
        var _tempSqrtDis = calcDis(currentRect, val.item.rect)
        if (val.dis === dis && _tempSqrtDis < _sqrtDis) {
          _sqrtDis = _tempSqrtDis
          _select.item = val.item
        }
      })
      return _select.item;
    },
    /**区域算法 */
    onAreaAlgorithm: function (widgetItem, widgetList, direction) {
      var currentWidget = widgetItem.container, currentRect = widgetItem.rect, _select = { item: null, }, dis = Infinity, tempDis;
      for (var i = 0; i < widgetList.length; i++) {
        var tempWidget = widgetList[i].container;
        if (widgetList[i].name === _defConfig.boxClass && !Utils.find(Utils.$class(_defConfig.widgetClass, tempWidget), function (e) { return !Utils.isEleHide(e) })) continue;
        if (tempWidget === currentWidget) continue;
        var tempWidgetRect = widgetList[i].rect;
        if (tempWidgetRect.height == 0 || tempWidgetRect.width == 0) continue;
        if (direction === _defConfig.keyEnum.LEFT && tempWidgetRect.right <= currentRect.left) {
          tempDis = Infinity;
          if (tempWidgetRect.bottom < currentRect.top) {
            tempDis = Math.sqrt(Math.pow(currentRect.left - tempWidgetRect.right, 2) + Math.pow(currentRect.top - tempWidgetRect.bottom, 2));
          } else if (tempWidgetRect.top > currentRect.bottom) {
            tempDis = Math.sqrt(Math.pow(currentRect.left - tempWidgetRect.right, 2) + Math.pow(tempWidgetRect.top - currentRect.bottom, 2));
          } else {
            tempDis = currentRect.left - tempWidgetRect.right;
          }
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          }
        } else if (direction === _defConfig.keyEnum.RIGHT && tempWidgetRect.left >= currentRect.right) {
          tempDis = Infinity;
          if (tempWidgetRect.bottom < currentRect.top) {
            tempDis = Math.sqrt(Math.pow(tempWidgetRect.left - currentRect.right, 2) + Math.pow(currentRect.top - tempWidgetRect.bottom, 2));
          } else if (tempWidgetRect.top > currentRect.bottom) {
            tempDis = Math.sqrt(Math.pow(tempWidgetRect.left - currentRect.right, 2) + Math.pow(tempWidgetRect.top - currentRect.bottom, 2));
          } else {
            tempDis = tempWidgetRect.left - currentRect.right;
          }
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          }
        } else if (direction === _defConfig.keyEnum.UP && tempWidgetRect.bottom <= currentRect.top) {
          tempDis = Infinity;
          if (tempWidgetRect.right < currentRect.left) {
            tempDis = Math.sqrt(Math.pow(currentRect.top - tempWidgetRect.bottom, 2) + Math.pow(currentRect.left - tempWidgetRect.right, 2));
          } else if (tempWidgetRect.left > currentRect.right) {
            tempDis = Math.sqrt(Math.pow(currentRect.top - tempWidgetRect.bottom, 2) + Math.pow(tempWidgetRect.left - currentRect.right, 2));
          } else {
            tempDis = currentRect.top - tempWidgetRect.bottom;
          }
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          }
        } else if (direction === _defConfig.keyEnum.DOWN && tempWidgetRect.top >= currentRect.bottom) {
          tempDis = Infinity;
          if (tempWidgetRect.right < currentRect.left) {
            tempDis = Math.sqrt(Math.pow(tempWidgetRect.top - currentRect.bottom, 2) + Math.pow(currentRect.left - tempWidgetRect.right, 2));
          } else if (tempWidgetRect.left > currentRect.right) {
            tempDis = Math.sqrt(Math.pow(tempWidgetRect.top - currentRect.bottom, 2) + Math.pow(tempWidgetRect.left - currentRect.right, 2));
          } else {
            tempDis = tempWidgetRect.top - currentRect.bottom;
          }
          if (tempDis < dis) {
            _select.item = widgetList[i];
            dis = tempDis;
          }
        }
      }
      return _select.item;
    },
  };
  window.LyFocusFrame = FocusFrame// 公开API -------------------------------------------------
})(window);